home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / glibmm-2.4 / proc / pm / DocsParser.pm next >
Text File  |  2006-04-20  |  13KB  |  476 lines

  1. # gtkmm - DocsParser module
  2. #
  3. # Copyright 2001 Free Software Foundation
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  18. #
  19.  
  20. # Based on XML::Parser tutorial found at http://www.devshed.com/Server_Side/Perl/PerlXML/PerlXML1/page1.html
  21. # This module isn't properly Object Orientated because the XML Parser needs global callbacks.
  22.  
  23. package DocsParser;
  24. use XML::Parser;
  25. use strict;
  26. use warnings;
  27.  
  28. # use Util;
  29. use Function;
  30. use GtkDefs;
  31. use Object;
  32.  
  33. BEGIN {
  34.      use Exporter   ();
  35.      our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
  36.  
  37.      # set the version for version checking
  38.      $VERSION     = 1.00;
  39.  
  40.      @ISA         = qw(Exporter);
  41.      @EXPORT      = ( );
  42.      %EXPORT_TAGS = ( );
  43.  
  44.      # your exported package globals go here,
  45.      # as well as any optionally exported functions
  46.      @EXPORT_OK   = ( );
  47. }
  48. our @EXPORT_OK;
  49.  
  50. #####################################
  51.  
  52. use strict;
  53. use warnings;
  54.  
  55. #####################################
  56.  
  57. $DocsParser::CurrentFile = "";
  58.  
  59. $DocsParser::refAppendTo = undef; # string reference to store the data into
  60. $DocsParser::currentParam = undef;
  61.  
  62. $DocsParser::objCurrentFunction = undef; #Function
  63. %DocsParser::hasharrayFunctions = (); #Function elements
  64. #~ $DocsParser::bOverride = 0; #First we parse the C docs, then we parse the C++ override docs.
  65.  
  66. $DocsParser::commentStart = "  /** ";
  67. $DocsParser::commentMiddleStart = "   * ";
  68. $DocsParser::commentEnd = "   */";
  69.  
  70. sub read_defs($$$)
  71. {
  72.   my ($path, $filename, $filename_override) = @_;
  73.   
  74.   my $objParser = new XML::Parser(ErrorContext => 0);
  75.   $objParser->setHandlers(Start => \&parse_on_start, End => \&parse_on_end, Char => \&parse_on_cdata);
  76.   
  77.   # C documentation:
  78.   $DocsParser::CurrentFile = "$path/$filename";
  79.   if ( ! -r $DocsParser::CurrentFile)
  80.   {
  81.      print "DocsParser.pm: Warning: Can't read file \"" . $DocsParser::CurrentFile . "\".\n";
  82.      return;
  83.   }
  84.   # Parse
  85.   eval { $objParser->parsefile($DocsParser::CurrentFile) };
  86.   if( $@ )
  87.   {
  88.     $@ =~ s/at \/.*?$//s;
  89.     print "\nError in \"" . $DocsParser::CurrentFile . "\":$@\n";
  90.     return;
  91.   }
  92.  
  93.   # C++ overide documentation:
  94.   $DocsParser::CurrentFile = "$path/$filename_override";
  95.   if ( ! -r $DocsParser::CurrentFile)
  96.   {
  97.      print "DocsParser.pm: Warning: Can't read file \"" . $DocsParser::CurrentFile . "\".\n";
  98.      return;
  99.   }
  100.   # Parse
  101.   eval { $objParser->parsefile($DocsParser::CurrentFile) };
  102.   if( $@ )
  103.   {
  104.     $@ =~ s/at \/.*?$//s;
  105.     print "\nError in \"" . $DocsParser::CurrentFile . "\":$@";
  106.     return;
  107.   }
  108. }
  109.  
  110. sub parse_on_start($$%)
  111. {
  112.   my ($objParser, $tag, %attr) = @_;
  113.  
  114.   $tag = lc($tag);
  115.  
  116.   if($tag eq "function")
  117.   {
  118.     if(defined $DocsParser::objCurrentFunction)
  119.     {
  120.       $objParser->xpcroak("\nClose a function tag before you open another one.");
  121.     }
  122.     
  123.     my $functionName = $attr{name};
  124.  
  125.     #Reuse existing Function, if it exists:
  126.     #(For instance, if this is the override parse)
  127.     $DocsParser::objCurrentFunction = $DocsParser::hasharrayFunctions{$functionName};
  128.     if(!$DocsParser::objCurrentFunction)
  129.     {
  130.       #Make a new one if necessary:
  131.       $DocsParser::objCurrentFunction = Function::new_empty();
  132.       # The idea is to change the policy a bit:
  133.       # If a function is redefined in a later parsing run only values which are redefined
  134.       # will be overwritten. For the name this is trivial. The description is simply rewritten.
  135.       # Same goes for the return description and the class mapping. Only exception is the
  136.       # parameter list. Everytime we enter a <parameters> tag the list is emptied again.
  137.       $$DocsParser::objCurrentFunction{name} = $functionName;
  138.       $$DocsParser::objCurrentFunction{description} = "";
  139.       $$DocsParser::objCurrentFunction{param_names} = [];
  140.       $$DocsParser::objCurrentFunction{param_descriptions} = ();
  141.       $$DocsParser::objCurrentFunction{return_description} = "";
  142.       $$DocsParser::objCurrentFunction{mapped_class} = "";
  143.       # We don't need this any more, the only reference to this field is commented
  144.       # $$DocsParser::objCurrentFunction{description_overridden} = $DocsParser::bOverride;
  145.     }
  146.   }
  147.   elsif($tag eq "parameters")
  148.   {
  149.     $$DocsParser::objCurrentFunction{param_names} = [];
  150.     $$DocsParser::objCurrentFunction{param_descriptions} = ();
  151.   }
  152.   elsif($tag eq "parameter")
  153.   {
  154.     $DocsParser::currentParam = $attr{name};
  155.     $$DocsParser::objCurrentFunction{param_descriptions}->{$DocsParser::currentParam} = "";
  156.   }
  157.   elsif($tag eq "description")
  158.   {
  159.     $$DocsParser::objCurrentFunction{description} = "";
  160.     # Set destination for parse_on_cdata().
  161.     $DocsParser::refAppendTo = \$$DocsParser::objCurrentFunction{description};
  162.   }
  163.   elsif($tag eq "parameter_description")
  164.   {
  165.     # Set destination for parse_on_cdata().
  166.     my $param_desc = \$$DocsParser::objCurrentFunction{param_descriptions};
  167.     $DocsParser::refAppendTo = \$$param_desc->{$DocsParser::currentParam};
  168.   }
  169.   elsif($tag eq "return")
  170.   {
  171.     $$DocsParser::objCurrentFunction{return_description} = "";
  172.     # Set destination for parse_on_cdata().
  173.     $DocsParser::refAppendTo = \$$DocsParser::objCurrentFunction{return_description};
  174.   }
  175.   elsif($tag eq "mapping")
  176.   {
  177.     $$DocsParser::objCurrentFunction{mapped_class} = $attr{class};
  178.   }
  179.   elsif($tag ne "root")
  180.   {
  181.     $objParser->xpcroak("\nUnknown tag \"$tag\".");
  182.   }
  183. }
  184.  
  185.  
  186. sub parse_on_end($$)
  187. {
  188.   my ($parser, $tag) = @_;
  189.  
  190.   # Clear destination for parse_on_cdata().
  191.   $DocsParser::refAppendTo = undef;
  192.  
  193.   $tag = lc($tag);
  194.  
  195.   if($tag eq "function")
  196.   {
  197.     # Store the Function structure in the array:
  198.     my $functionName = $$DocsParser::objCurrentFunction{name};
  199.     $DocsParser::hasharrayFunctions{$functionName} = $DocsParser::objCurrentFunction;
  200.     $DocsParser::objCurrentFunction = undef;
  201.   }
  202.   elsif($tag eq "parameter")
  203.   {
  204.     # <parameter name="returns"> and <return> means the same.
  205.     if($DocsParser::currentParam eq "returns")
  206.     {
  207.       my $param_descriptions = \$$DocsParser::objCurrentFunction{param_descriptions};
  208.       my $return_description = \$$DocsParser::objCurrentFunction{return_description};
  209.       $$return_description = delete $$param_descriptions->{"returns"};
  210.     }
  211.     else
  212.     {
  213.       # Append to list of parameters.
  214.       push(@{$$DocsParser::objCurrentFunction{param_names}}, $DocsParser::currentParam);
  215.     }
  216.  
  217.     $DocsParser::currentParam = undef;
  218.   }
  219. }
  220.  
  221.  
  222. sub parse_on_cdata($$)
  223. {
  224.   my ($parser, $data) = @_;
  225.  
  226.   if(defined $DocsParser::refAppendTo)
  227.   {
  228.     # Dispatch $data to the current destination string.
  229.     $$DocsParser::refAppendTo .= $data;
  230.   }
  231. }
  232.  
  233.  
  234. # $strCommentBlock lookup_documentation($strFunctionName)
  235. sub lookup_documentation($)
  236. {
  237.   my ($functionName) = @_;
  238.    
  239.   my $objFunction = $DocsParser::hasharrayFunctions{$functionName};
  240.   if(!$objFunction)
  241.   {
  242.     #print "DocsParser.pm: Warning: function not found: $functionName\n";
  243.     return ""
  244.   }
  245.   
  246.   my $text = $$objFunction{description};
  247.  
  248.   if(length($text) eq 0)
  249.   {
  250.     print "DocsParser.pm: Warning: No C docs for function: \"$functionName\"\n";
  251.   }
  252.   
  253.       
  254.   DocsParser::convert_docs_to_cpp($objFunction, \$text);
  255.   DocsParser::append_parameter_docs($objFunction, \$text);
  256.   DocsParser::append_return_docs($objFunction, \$text);
  257.  
  258.     
  259.   # Escape the space after "i.e." or "e.g." in the brief description.
  260.   $text =~ s/^([^.]*\b(?:i\.e\.|e\.g\.))\s/$1\\ /;
  261.       
  262.   # Convert to Doxygen-style comment.
  263.   $text =~ s/\n/\n${DocsParser::commentMiddleStart}/g;
  264.   $text =  $DocsParser::commentStart . $text;
  265.   $text .= "\n${DocsParser::commentEnd}\n";
  266.       
  267.   return $text;
  268. }
  269.  
  270.  
  271. sub append_parameter_docs($$)
  272. {
  273.   my ($obj_function, $text) = @_;
  274.  
  275.   my @param_names = @{$$obj_function{param_names}};
  276.   my $param_descriptions = \$$obj_function{param_descriptions};
  277.  
  278.   # Strip first parameter if this is a method.
  279.   my $defs_method = GtkDefs::lookup_method_dont_mark($$obj_function{name});
  280.   # the second alternative is for use with method-mappings meaning:
  281.   # this function is mapped into this Gtk::class
  282.   shift(@param_names) if(($defs_method && $$defs_method{class} ne "") ||
  283.                          ($$obj_function{mapped_class} ne ""));
  284.  
  285.   foreach my $param (@param_names)
  286.   {
  287.     my $desc = $$param_descriptions->{$param};
  288.     
  289.     $param =~ s/([a-zA-Z0-9]*(_[a-zA-Z0-9]+)*)_?/$1/g;
  290.     DocsParser::convert_docs_to_cpp($obj_function, \$desc);
  291.     if(length($desc) > 0)
  292.     {
  293.       $desc  .= '.' unless($desc =~ /(?:^|\.)$/);
  294.       $$text .= "\n\@param ${param} \u${desc}";
  295.     }
  296.   }
  297. }
  298.  
  299.  
  300. sub append_return_docs($$)
  301. {
  302.   my ($obj_function, $text) = @_;
  303.  
  304.   my $desc = $$obj_function{return_description};
  305.   DocsParser::convert_docs_to_cpp($obj_function, \$desc);
  306.  
  307.   $desc  =~ s/\.$//;
  308.   $$text .= "\n\@return \u${desc}." unless($desc eq "");
  309. }
  310.  
  311.  
  312. sub convert_docs_to_cpp($$)
  313. {
  314.   my ($obj_function, $text) = @_;
  315.  
  316.   # Chop off leading and trailing whitespace.
  317.   $$text =~ s/^\s+//;
  318.   $$text =~ s/\s+$//;
  319. # HagenM: this is the only reference to $$obj_function{description_overridden}
  320. # and it seems not to be in use.
  321. #  if(!$$obj_function{description_overridden})
  322. #  {
  323.     # Convert C documentation to C++.
  324.     DocsParser::convert_tags_to_doxygen($text);
  325.     DocsParser::substitute_identifiers($$obj_function{name}, $text);
  326.  
  327.     $$text =~ s/\bX\s+Window\b/X \%Window/g;
  328.     $$text =~ s/\bWindow\s+manager/\%Window manager/g;
  329. #  }
  330. }
  331.  
  332.  
  333. sub convert_tags_to_doxygen($)
  334. {
  335.   my ($text) = @_;
  336.  
  337.   for($$text)
  338.   {
  339.     # Replace format tags.
  340.     s"<(/?)emphasis>"<$1em>"g;
  341.     s"<(/?)literal>"<$1tt>"g;
  342.     s"<(/?)function>"<$1tt>"g;
  343.  
  344.     # Some argument names are suffixed by "_" -- strip this.
  345.     # gtk-doc uses @thearg, but doxygen uses @a thearg.
  346.     s" ?\@([a-zA-Z0-9]*(_[a-zA-Z0-9]+)*)_?\b" \@a $1 "g;
  347.     s"^Note ?\d?: "\@note "mg;
  348.  
  349.     s"</?programlisting>""g;
  350.     s"<informalexample>"\@code"g;
  351.     s"</informalexample>"\@endcode"g;
  352.     s"<!>""g;
  353.  
  354.     # Remove all link tags.
  355.     s"</?u?link[^&]*>""g;
  356.  
  357.     # Remove all para tags (from tmpl sgml files).
  358.     s"</?para>""g;
  359.  
  360.     s"\b->\b"->"g;
  361.  
  362.     # Doxygen is too dumb to handle —
  363.     s"—" \@htmlonly—\@endhtmlonly "g;
  364.  
  365.     s"\%?FALSE\b"<tt>false</tt>"g;
  366.     s"\%?TRUE\b"<tt>true</tt>"g;
  367.     s"\%?NULL\b"<tt>0</tt>"g;
  368.  
  369.     s"#?\bgboolean\b"<tt>bool</tt>"g;
  370.     s"#?\bg(int|short|long)\b"<tt>$1</tt>"g;
  371.     s"#?\bgu(int|short|long)\b"<tt>unsigned $1</tt>"g;
  372.  
  373.     # For Gtk::TextIter.
  374.     s"(\\[rn])\b"<tt>\\$1</tt>"g;
  375.   }
  376. }
  377.  
  378.  
  379. sub substitute_identifiers($$)
  380. {
  381.   my ($doc_func, $text) = @_;
  382.  
  383.   for($$text)
  384.   {
  385.     # TODO: handle more than one namespace
  386.  
  387.     s/[#%]([A-Z][a-z]*)([A-Z][A-Za-z]+)\b/$1::$2/g; # type names
  388.  
  389.     s/[#%]([A-Z])([A-Z]*)_([A-Z\d_]+)\b/$1\L$2\E::$3/g; # enum values
  390.  
  391.     # Undo wrong substitutions.
  392.     s/\bHas::/HAS_/g;
  393.     s/\bNo::/NO_/g;
  394.  
  395.     # Replace C function names with C++ counterparts.
  396.     s/\b([a-z]+_[a-z][a-z\d_]+) ?\(\)/&DocsParser::substitute_function($doc_func, $1)/eg;
  397.   }
  398. }
  399.  
  400.  
  401. sub substitute_function($$)
  402. {
  403.   my ($doc_func, $name) = @_;
  404.  
  405.   if(my $defs_method = GtkDefs::lookup_method_dont_mark($name))
  406.   {
  407.     if(my $defs_object = DocsParser::lookup_object_of_method($$defs_method{class}, $name))
  408.     {
  409.       my $module = $$defs_object{module};
  410.       my $class  = $$defs_object{name};
  411.  
  412.       DocsParser::build_method_name($doc_func, $module, $class, \$name);
  413.     }
  414.   }
  415.   else
  416.   {
  417.     # Not perfect, but better than nothing.
  418.     $name =~ s/^g_/Glib::/;
  419.   }
  420.  
  421.   return $name . "()";
  422. }
  423.  
  424.  
  425. sub lookup_object_of_method($$)
  426. {
  427.   my ($object, $name) = @_;
  428.  
  429.   if($object ne "")
  430.   {
  431.     # We already know the C object name, because $name is a non-static method.
  432.     return GtkDefs::lookup_object($object);
  433.   }
  434.  
  435.   my @parts = split(/_/, $name);
  436.   pop(@parts);
  437.  
  438.   # (gtk, foo, bar) -> (Gtk, Foo, Bar)
  439.   foreach(@parts) { $_ = (length > 2) ? ucfirst : uc; }
  440.  
  441.   # Do a bit of try'n'error.
  442.   while(scalar(@parts) > 1)
  443.   {
  444.     my $try = join("", @parts);
  445.  
  446.     if(my $defs_object = GtkDefs::lookup_object($try))
  447.       { return $defs_object; }
  448.  
  449.     pop(@parts);
  450.   }
  451.  
  452.   return undef;
  453. }
  454.  
  455.  
  456. sub build_method_name($$$$)
  457. {
  458.   my ($doc_func, $module, $class, $name) = @_;
  459.  
  460.   my $prefix = $module . $class;
  461.  
  462.   $prefix =~ s/([a-z])([A-Z])/$1_$2/g;
  463.   $prefix = lc($prefix) . '_';
  464.  
  465.   if($$name =~ /^$prefix/)
  466.   {
  467.     my $scope = "";
  468.     $scope = "${module}::${class}::" unless($doc_func =~ /^$prefix/);
  469.  
  470.     substr($$name, 0, length($prefix)) = $scope;
  471.   }
  472. }
  473.  
  474.  
  475. 1; # indicate proper module load.
  476.